package com.zxq.modbus.utils;


import lombok.extern.slf4j.Slf4j;

import java.util.HashMap;
import java.util.Map;

@Slf4j
public class ModBusCrc implements IModelCrc {

    byte[] srcBytes = null;
    byte[] dstBytes = null;


    /**
     * 03   指令  读单个寄存器指令
     * 06   指令  写单个寄存器指令
     * 05	指令	 单继电器操作指令
     * 0F	指令  多继电器操作指令
     * 10	指令	 预置多个保持寄存器数值
     */
    final byte READ_SINGLE = 0x03;
    final byte WRITE_SINGLE = 0x06;
    final byte OPERATION_SINGLE = 0x05;
    final byte OPERATION_MORE = 0x0F;
    final byte PRECUT_MORE = 0x10;
    final byte ERROR_CODE = (byte) 0x85;


    /**
     * 是否为合法帧
     * @param frame
     * @return
     */
    @Override
    public boolean isLegalFrame(byte[] frame) {
        int dataLen = frame.length - 2;
        byte[] dataBuff = new byte[dataLen];
        System.arraycopy(frame,0,dataBuff,0,dataBuff.length);
        byte[] crcBuff = new byte[2];
        System.arraycopy(frame,0,dataBuff,0,dataBuff.length);
        System.arraycopy(frame,frame.length - 2,crcBuff,0,crcBuff.length);
        byte[] selfCrcBuff = CrcUtils.makefcs(dataBuff);
        if(crcBuff[0] == selfCrcBuff[0] && crcBuff[1] == selfCrcBuff[1]) {
            return true;
        }
//        log.info("frame:" + HexBin.encode(frame));
//        log.info("data:" + HexBin.encode(dataBuff));
//        log.info("crc:" + HexBin.encode(crcBuff));
//        log.info("selfCrc:" + HexBin.encode(selfCrcBuff));
        return false;
    }

    @Override
    public void injectSrcBytes(byte[] srcBuff) {
         this.srcBytes = srcBuff;
    }

    @Override
    public void injectDstBytes(byte[] dstBuff) {
        this.dstBytes = dstBuff;
    }

    /**
     * 01 03 00   00 00 0C 45 CF
     * 01 03 18   00FB    0170   01DF  36EF0000  0017  001F  0040    01C8  00BE   019F   0040   5621
     *           空气湿度   温度    CO2    光照      氮    磷     钾     湿度   温度   电导率    pH   验证码
     */

    @Override
    public byte[] getModbusData() {

        int len = Math.abs(dstBytes[2]);
        byte[] modBuff = new byte[len];
        System.arraycopy(srcBytes,3,modBuff,0,modBuff.length);

        return modBuff;
    }


    @Override
    public boolean isModelBus(byte deviceByte, byte funByte) {
        if(srcBytes[0] == deviceByte && srcBytes[1] == funByte) {
            return true;
        }
        return false;
    }


    /**
     * 注意是 根据src帧来确定对应的帧
     * 写入的帧何读取的帧长度一样
     * 读取的帧长度3（设备地址1，指令1，长度1）
     * @return
     */
    @Override
    public int measureFrameLen() {
        int len = -1;
        switch (srcBytes[1]) {
            case READ_SINGLE:
               len = 3 + ((srcBytes[4]&0xff) * 256 + srcBytes[5]&0xff) * 2 + 2;
               break;
            case WRITE_SINGLE:
                len = 8;
                break;
            case OPERATION_SINGLE:
                len = 8;
                break;
            case OPERATION_MORE:
                len = 8;
                break;
            case PRECUT_MORE:
                len = 8;
                break;
            case ERROR_CODE:
                len = 5;
                break;
            default:
                len = -1;
                break;
           }

           return len;
    }




    /**
     * 010620030002F3CB     01030100000185F6
     * 010620030002F3CB     01030200C0B814
     * @return
     */
    @Override
    public Map<Integer, byte[]> getAdrValue() {
        Map<Integer, byte[]> maps = new HashMap<>();
        Integer startAdr =  (srcBytes[2] & 0xff) * 256 + srcBytes[3] & 0xff;
        if(srcBytes[1] == WRITE_SINGLE) {
              maps.put(startAdr,new byte[]{srcBytes[4],srcBytes[5]});
        }
        if(srcBytes[1] == READ_SINGLE) {
            Integer len = (srcBytes[4] & 0xff) * 256 + srcBytes[5] & 0xff;
            for(int i = 0; i < len; i++) {
                Integer adr = startAdr + i;
               // System.out.println("adr:" + adr);
                //4,5  6,7  8,9  10,11
                byte[] value = new byte[]{dstBytes[3 + 2 * i],dstBytes[3 + 2 * i + 1]};
                maps.put(adr,value);
            }
        }

        return maps;
    }






}
